﻿#region Header
// ------------------------ Licence / Copyright ------------------------
// 
// ScrumTable for Scrum Meeting Support
// Copyright © HSR - Hochschule für Technik Rapperswil
// All Rights Reserved
// 
// Author:
//  Michael Gfeller Silvan Gehrig Patrick Boos
// 
// ---------------------------------------------------------------------
#endregion

#region Usings

using System;
using System.Linq;

using ScrumTable.Common;
using ScrumTable.Common.Collections;
using ScrumTable.DL.Data.Generic.Cache;
using ScrumTable.DL.Data.Generic.Properties;
using ScrumTable.DL.Data.Schema;

#endregion

namespace ScrumTable.DL.Data.Generic
{
    /// <summary>
    /// This class contains the common data object facilities which
    /// are used in conjunction with workitem based data objects.
    /// </summary>
    internal abstract class WorkItemDataObjectBase<T> : DataObjectBase<T, CacheWorkItem>
        where T : SchemaBase
    {
        #region Declarations
        //--------------------------------------------------------------------
        // Declarations
        //--------------------------------------------------------------------

        #endregion

        #region Properties
        //--------------------------------------------------------------------
        // Properties
        //--------------------------------------------------------------------

        /// <summary>
        /// Gets the underlying data element instance.
        /// </summary>
        protected override CacheWorkItem Element { get { return WorkItem; } }

        /// <summary>
        /// Gets the underlying TfsWorkItem data object.
        /// </summary>
        internal CacheWorkItem WorkItem { get; private set; }

        #endregion

        #region Constructors / Destructor
        //--------------------------------------------------------------------
        // Constructors / Destructor
        //--------------------------------------------------------------------

        /// <summary>
        /// Creates a new WorkItemDataObjectBase instance, no public constructor
        /// needed.
        /// </summary>
        protected WorkItemDataObjectBase(DataAccessObjectBase parent, CacheWorkItem workItem)
            : base(parent)
        {
            PreCondition.AssertNotNull(workItem, "workItem");

            foreach (SchemaBase schema in Schema.Schemata)
            {
                if (schema.IsCustomSchema)
                {
                    NameSchemaMappings.Add(schema, GetUserDefinedValue, SetUserDefinedValue);
                }
            }

            WorkItem = workItem;
            WorkItem.PropertyChanged += OnDataPropertyChanged;
            WorkItem.PropertyChanging += OnDataPropertyChanging;
        }

        #endregion

        #region Methods
        //--------------------------------------------------------------------
        // Methods
        //--------------------------------------------------------------------

        /// <summary>
        /// Releases managed (c# or .net) resources.
        /// </summary>
        protected override void ReleaseManagedResources()
        {
            base.ReleaseManagedResources();
            WorkItem.PropertyChanging -= OnDataPropertyChanging;
            WorkItem.PropertyChanged -= OnDataPropertyChanged;
        }

        private object GetUserDefinedValue(SchemaBase schema) { return WorkItem[schema.SchemaMappedName]; }
        private void SetUserDefinedValue(SchemaBase schema, object toSet) { WorkItem[schema.SchemaMappedName] = toSet; }


        #region Value Check Methods

        /// <summary>
        /// Checks if the specified schema field has the corresponding value type and throws an
        /// exception if the value to set has an invalid type.
        /// </summary>
        /// <param name="schemaField">Specifies the schema field definition with the underlying schema data.</param>
        /// <param name="value">Specifies the value to check.</param>
        protected override void CheckValueType(SchemaBase schemaField, object value)
        {
            if (value == null) { return; }

            CacheFieldDefinition fieldDef = WorkItem.Type.TryGetFieldByBackEndId(schemaField.SchemaMappedName);

            if (fieldDef == null || !schemaField.IsCustomSchema)
            {
                base.CheckValueType(schemaField, value);
            }
            else if (!fieldDef.FieldType.IsAssignableFrom(value.GetType()))
            {
                throw new ArgumentException(string.Format(Resources.ExcDataObjArgTypeInvalid, schemaField.SchemaName, schemaField.SchemaType.FullName), "value");
            }
        }

        /// <summary>
        /// Checks if the specified schema field has the corresponding allowed values type and throws an
        /// exception if the value to set is not contained in the schema definition.
        /// </summary>
        /// <param name="schemaField">Specifies the schema field definition with the underlying schema data.</param>
        /// <param name="value">Specifies the value to check.</param>
        protected override void CheckAllowedValues(SchemaBase schemaField, object value)
        {
            if (value == null) { return; }

            CacheFieldDefinition fieldDef = WorkItem.Type.TryGetFieldByBackEndId(schemaField.SchemaMappedName);

            if (fieldDef == null || schemaField.IsSchemaReference)
            {
                // for compatibility with schema properties
                base.CheckAllowedValues(schemaField, value);
            }
            else if (fieldDef.HasAllowedValues && !fieldDef.AllowedValues.Contains(value))
            {
                throw new ArgumentException(string.Format(Resources.ExcDataObjArgValueInvalid, value, schemaField.SchemaName), "value");
            }
        }

        #endregion


        #endregion

        #region Events
        //--------------------------------------------------------------------
        // Events
        //--------------------------------------------------------------------

        #endregion
    }
}